package juc.executors;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class CompletableFutureExample4 {
    public static void main(String[] args) throws InterruptedException {
        //thenAcceptBoth();
        //acceptEither();
        //runAfterBoth();
        //runAfterEither();
        //thenCombine();
        thenCompose();
        Thread.currentThread().join();

    }

    private static void thenAcceptBoth() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the supplyAsync");
            timeSleep(5);
            System.out.println("end the supplyAsync");
            return "thenAcceptBoth";
        }).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
            System.out.println("start the thenAcceptBoth");
            timeSleep(3);
            System.out.println("end the thenAcceptBoth");
            return 100;
        }), (s, i) -> System.out.println(s + "--" + i));

    }

    /**
     * 都会执行，结果取其中一个先执行完的
     */
    private static void acceptEither() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the acceptEither1");
            timeSleep(5);
            System.out.println("end the acceptEither1");
            return "acceptEither-1";
        }).acceptEither(CompletableFuture.supplyAsync(() -> {
            System.out.println("start the acceptEither2");
            timeSleep(3);
            System.out.println("end the acceptEither2");
            return "acceptEither-2";
        }), System.out::println);

    }


    private static void runAfterBoth() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the runAfterBoth1");
            timeSleep(5);
            System.out.println("end the runAfterBoth1");
            return "runAfterBoth-1";
        }).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
            System.out.println("start the runAfterBoth2");
            timeSleep(3);
            System.out.println("end the runAfterBoth2");
            return 100;
        }), () -> System.out.println("done"));
    }

    private static void runAfterEither() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the runAfterEither1");
            timeSleep(5);
            System.out.println("end the runAfterEither1");
            return "runAfterEither-1";
        }).runAfterEither(CompletableFuture.supplyAsync(() -> {
            System.out.println("start the runAfterEither2");
            timeSleep(3);
            System.out.println("end the runAfterEither2");
            return 100;
        }), () -> System.out.println("done"));
    }

    private static void thenCombine() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the thenCombine1");
            timeSleep(5);
            System.out.println("end the thenCombine1");
            return "thenCombine-1";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println("start the thenCombine2");
            timeSleep(3);
            System.out.println("end the thenCombine2");
            return 100;
        }), (s, i) -> s.length() + "--" + i).whenComplete((v, t) -> System.out.println(v));
    }

    private static void thenCompose() {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("start the thenCompose1");
            timeSleep(5);
            System.out.println("end the thenCompose1");
            return "thenCompose-1";
        }).thenCompose(
                s -> CompletableFuture.supplyAsync(() -> {
                    System.out.println("start the thenCompose2");
                    timeSleep(3);
                    System.out.println("end the thenCompose2");
                    return s.length();
                })).thenAccept(System.out::println);
    }

    /**
     * sleep the specify seconds
     */
    private static void timeSleep(long time) {
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
